package com.eastseeway.radioproject.tcp;

import android.util.Log;

import com.eastseeway.radioproject.unlock.UnlockViewModel;
import com.eastseeway.radioproject.utils.ByteUtil;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class TcpClient {
    private final String host;
    private final int port;
    private final TcpCallback callback;
    private Socket socket;
    private DataInputStream input;
    private DataOutputStream output;
    private volatile boolean isConnected = false;
    private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);

    public TcpClient(String host, int port, TcpCallback callback) {
        this.host = host;
        this.port = port;
        this.callback = callback;
    }

    public void connect() {
        Log.d("TcpClient", "Connecting to " + host + ":" + port);
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    closeResources();
                    callback.onConnectionStateChanged(TcpCallback.ConnectionState.CONNECTING);

                    socket = new Socket(host, port);
                    input = new DataInputStream(socket.getInputStream());
                    output = new DataOutputStream(socket.getOutputStream());
                    isConnected = true;

                    callback.onConnectionStateChanged(TcpCallback.ConnectionState.CONNECTED);
                    startReceiveLoop();
                } catch (IOException e) {
                    handleError("Connection failed: " + e.getMessage());
                }

            }
        });
    }

    private void startReceiveLoop() {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                byte[] buffer = new byte[1360];
                try {
                    while (isConnected) {
                        int bytesRead = input.read(buffer);
                        if (bytesRead == -1) break;

                        byte[] data = new byte[bytesRead];
                        System.arraycopy(buffer, 0, data, 0, bytesRead);
                        callback.onDataReceived(data);
                    }
                } catch (IOException e) {
                    handleError("Receive error: " + e.getMessage());
                } finally {
                    if (isConnected) {
                        disconnect();
                    }
                }
            }
        });
    }

    public void sendData(byte[] data) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                if (!isConnected) {
                    handleError("Not connected to server");
                    return;
                }

                try {
                    output.write(data);
                    Log.e("12121", "DirectSendMsg: " + ByteUtil.ByteArrToHex(data));
                    output.flush();
                } catch (IOException e) {
                    handleError("Send failed: " + e.getMessage());
                }
            }
        });
    }

    private void handleError(String error) {
        callback.onErrorOccurred("handleError:"+error);
        disconnect();
        scheduleReconnect();
    }

    private void scheduleReconnect() {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    callback.onConnectionStateChanged(TcpCallback.ConnectionState.RECONNECTING);
                    connect();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
    }

    public void disconnect() {
        isConnected = false;
        closeResources();
        callback.onConnectionStateChanged(TcpCallback.ConnectionState.DISCONNECTED);
    }

    private void closeResources() {
        try {
            if (input != null) input.close();
            if (output != null) output.close();
            if (socket != null) socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
